Quote fewer characters, i.e. :, @, and + - #44
Merged
Conversation
This was
linked to
issues
Aug 7, 2026
allenap
force-pushed
the
quote-fewer-characters
branch
from
August 7, 2026 21:36
2a69d60 to
7825d59
Compare
Previously any one of these dragged a whole word into quotes, so a URL came out as `https'://github.com/allenap/shell-quote'`. That is correct but noisy, which rather undermines the claim that `Sh` output is "better for humans to read, to copy and paste". All three are inert wherever they land in a word, checked in leading, medial, and trailing position against `/bin/sh`, Bash 3.2 and 5.3, Dash, Z Shell 5.9, and fish 4.8. `%` and `=` were tried too, and would have addressed #8 as well, but they earned a guard that grew a new special case each time I looked at it – append assignments, `=` expansion, `MAGIC_EQUAL_SUBST`, job specifications – and two of those were found only after I had convinced myself the thing was correct. For a crate whose one job is to emit a single literal word, terser output is not worth that. They stay quoted, and the module documentation in `ascii.rs` now records every hazard found, and the reason a plain non-interactive `sh -c` probe fails to reveal them, so that the next person to try this starts where I left off rather than where I began. Closes #42.
allenap
force-pushed
the
quote-fewer-characters
branch
from
August 7, 2026 21:43
7825d59 to
717ab37
Compare
:, @, +, %, and usually =:, @, and +
In command position Bash reads a word beginning with `%` as a job specification, so `%1` on its own means `fg %1`, and quoting does not prevent it: Bash tests the word's value, after expansion and quote removal, so `%1`, `'%1'`, `"%1"`, `$'%1'`, `\%1`, and `""%1` all alike run `fg`. Nor does it depend on job control being enabled, which was my first guess. Bash rewrites the word either way and only the complaint differs, `fg: no job control` or `fg: %1: no such job`; the same holds with `set -m`, with `set +m`, under `--posix`, and in Bash 3.2. An executable named `%1` sitting on `PATH` will not be run, though it runs happily by an explicit path. Only the first character counts: `a%1` is an ordinary command name. Z Shell tests the literal token instead, so quoting does work there. That is why `%` is quoted unconditionally rather than only when it leads a word: it is what Z Shell needs, and it is at worst harmless in Bash. Worth keeping in proportion: this bites only in command position. As an argument, which is what this crate is mostly used for, `%` is an ordinary character in both shells.
allenap
force-pushed
the
quote-fewer-characters
branch
from
August 7, 2026 21:57
717ab37 to
5bfa942
Compare
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Previously any one of
:,@, or+dragged a whole word into quotes, so a URL came out ashttps'://github.com/allenap/shell-quote'. That is correct but noisy, which rather undermines the claim thatShoutput is "better for humans to read, to copy and paste". All three are inert wherever they land in a word; each was checked in leading, medial, and trailing position against/bin/sh, Bash 3.2 and 5.3, Dash, Z Shell 5.9, and fish 4.8. The change is four lines of the classifier, with no position tracking and no new state, and every pre-existing test passes unmodified.An earlier draft of this branch made
%and=inert too, which would have addressed #8, but they needed a guard to re-quote them where they are significant, and that guard grew a new special case every time I looked at it: assignments, the append formFOO+=bar,=expansion in Z Shell,MAGIC_EQUAL_SUBST, and job specifications. Two of those I found only after convincing myself the implementation was already correct. Every one is conditional on a shell option, on job control, or on whether the shell is interactive, none of which a plain non-interactivesh -cprobe exercises – which is precisely why they were missed. For a crate whose one job is to emit a single literal word, terser output isn't worth that, so%and=stay quoted and #8 stays open.There is a module-level note in
src/ascii.rsrecording every hazard found, along with the lookalikes that turn out to be harmless, so that a future attempt at this starts from there rather than from scratch.The second commit documents something related. A leading
%cannot be made safe as a command name in Bash by any means, because Bash tests the word's value after quote removal, so%1,'%1', and$'%1'alike runfg. It is not conditional on job control; that only changes the complaint. Z Shell tests the literal token instead, so quoting does work there – which is why%is quoted unconditionally rather than only when it leads a word.Closes #42.